/**
 * File: FastSequenceBoxReader.java
 * Created by: mhaimel
 * Created on: Jun 23, 2011
 * CVS:  $Id: FastSequenceBoxReader.java 1.0 Jun 23, 2011 4:44:09 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.storage.sequence.fast;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.storage.CompressorStrategy;
import uk.ac.ebi.curtain.storage.sequence.InputRandomAccessStream;
import uk.ac.ebi.curtain.storage.sequence.SequenceBox;
import uk.ac.ebi.curtain.storage.sequence.StreamProvider;
import uk.ac.ebi.curtain.utils.Pair;

/**
 * @author mhaimel
 *
 */
public class FastSequenceBoxReader implements Closeable {
	private Log log;
	private FastBlockReader stream;
	
	public FastSequenceBoxReader(File inputFile) {
		this.stream = new FastBlockReader(inputFile);
	}
	public FastSequenceBoxReader(File inputFile,CompressorStrategy strategry) {
		this.stream = new FastBlockReader(inputFile,strategry);
	}	
	public FastSequenceBoxReader(StreamProvider<InputRandomAccessStream> in, StreamProvider<InputStream> idx) {
		this.stream = new FastBlockReader(in,idx);
	}
	public FastSequenceBoxReader(StreamProvider<InputRandomAccessStream> in, StreamProvider<InputStream> idx,CompressorStrategy strategy) {
		this.stream = new FastBlockReader(in,idx,strategy);
	}
	public void open() throws IOException {
		this.stream.open();
	}

	@Override
	public void close() throws IOException {
		this.stream.close();
	}			
	private Log getLog() {
		if(null == log){
			log = LogFactory.getLog(this.getClass());
		}
		return log;
	}

	static Pair<Long, SequenceBox> _parseEntry(String s) {
		String[] arr = StringUtils.split(s, getSeparator());
		Long id = Long.valueOf(arr[0]);
		SequenceBox boxa = null;
		if(arr.length > 3){
			boxa =
				new SequenceBox(
					arr[1],
					arr[2],
					arr[3]);
		} else {
			boxa =
				new SequenceBox(
					arr[1],
					arr[2]);
		}
		return new Pair<Long,SequenceBox>(
				id,boxa);
	}
	
	public class FastBoxInterator implements Iterator<Pair<Long, SequenceBox>>{
		private Pair<Long, SequenceBox> next = null;
		private Iterator<String> lineIter;

		public FastBoxInterator(Iterator<String> lineIter) {
			this.lineIter = lineIter;
		}

		@Override
		public boolean hasNext() {
			while(lineIter.hasNext()){
				String line = lineIter.next();
				if(line == null){
					next = null;
					return false;
				}
				Pair<Long, SequenceBox> parseEntry = _parseEntry(line);
				if(valid(parseEntry)){
					next = parseEntry;
					return true;
				}
			}
			return false;
		}

		protected boolean valid(Pair<Long, SequenceBox> parseEntry) {
			return parseEntry != null;
		}

		@Override
		public Pair<Long, SequenceBox> next() {
			return next;
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException();
		}

	}
	
	public class FastBoxValidateInterator implements Iterator<SequenceBox>{
		private Long id;
		private FastBoxInterator iter;
		public FastBoxValidateInterator(Long id, Iterator<String> lineIter) {
			this.iter = new FastBoxInterator(lineIter);
			this.id = id;
		}

		protected boolean valid(Pair<Long, SequenceBox> parseEntry) {
			return parseEntry.getA().equals(id);
		}

		@Override
		public boolean hasNext() {
			if(iter.hasNext() && valid(iter.next())){
				return true;
			}
			return false;
		}

		@Override
		public SequenceBox next() {
			return iter.next().getB();
		}

		@Override
		public void remove() {
			iter.remove();
		}
	}

	private static char getSeparator() {
		return FastSequenceBoxWriter.getSeparator();
	}
	
	public Iterable<Pair<Long, SequenceBox>> getAllEntries(){
		final Iterator<String> iter = stream.getAllEntries().iterator();
		return new Iterable<Pair<Long, SequenceBox>>() {
			
			@Override
			public Iterator<Pair<Long, SequenceBox>> iterator() {
				return new FastBoxInterator(iter);
			}
		};
	}

	public Iterable<SequenceBox> getEntries(final Long id){
		final Iterator<String> lineIter = stream.getEntries(id).iterator();
		return new Iterable<SequenceBox>() {
			
			@Override
			public Iterator<SequenceBox> iterator() {
				return new FastBoxValidateInterator(id,lineIter);
			}
		};
	}

}
